package cn.bugDance.domain.strategy.service.rule.tree.engine;

import cn.bugDance.domain.strategy.model.entity.*;
import cn.bugDance.domain.strategy.model.valobj.DetermineTypeVO;
import cn.bugDance.domain.strategy.model.valobj.StrategyConstant;
import cn.bugDance.domain.strategy.repository.IStrategyRepository;
import cn.bugDance.domain.strategy.service.rule.tree.IRuleTree;
import cn.bugDance.domain.strategy.service.rule.tree.factory.RuleTreeFactory;
import cn.bugDance.types.enums.ResponseCode;
import cn.bugDance.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
public class DefaultRuleEngine implements IRuleEngine{

    private Map<String, IRuleTree> ruleTreeGroup;
    private IStrategyRepository strategyRepository;

    public DefaultRuleEngine(Map<String, IRuleTree> ruleTreeGroup,IStrategyRepository strategyRepository) {
        this.ruleTreeGroup = ruleTreeGroup;
        this.strategyRepository = strategyRepository;
    }

    @Override
    public RuleTreeFactory.RuleTreeActionEntity process(RuleTreeEntity ruleTreeEntity, RuleTreeFactorEntity ruleTreeFactorEntity) {
        log.info("【策略领域层-DefaultRuleEngine】: 规则规则树引擎执行, strategyId: {}, awardId: {}", ruleTreeEntity.getStrategyId(), ruleTreeFactorEntity.getAwardId());
        RuleTreeNodeEntity currNode = ruleTreeEntity.getRuleTreeNodeEntityGroup().get(ruleTreeEntity.getRootId());
        if(null == currNode){
            throw new AppException(ResponseCode.RULE_TREE_ERROR.getCode(), ResponseCode.RULE_TREE_ERROR.getInfo());
        }
        RuleTreeFactorEntity ruleTreeFactorEntityCopy = ruleTreeFactorEntity;
        while(true){
            IRuleTree ruleTree = ruleTreeGroup.get(currNode.getRuleModel());
            RuleTreeDetermineEntity ruleTreeDetermineEntity = ruleTree.action(ruleTreeFactorEntityCopy);
            ruleTreeFactorEntityCopy.setAwardId(ruleTreeDetermineEntity.getAwardId());

            DetermineTypeVO determineTypeVO = ruleTreeDetermineEntity.getDetermineTypeVO();
            RuleTreeLineEntity ruleTreeLineEntity = currNode.getRuleTreeLineEntityGroup().get(determineTypeVO.getCode());
            if(Objects.equals(ruleTreeLineEntity.getNodeTo(), StrategyConstant.LINE_OVER)){
                break;
            }
            currNode = ruleTreeEntity.getRuleTreeNodeEntityGroup().get(ruleTreeLineEntity.getNodeTo());
        }

        return RuleTreeFactory.RuleTreeActionEntity.builder()
                .award(ruleTreeFactorEntityCopy.getAwardId()).build();
    }

    @Override
    public RuleTreeEntity armory(Long strategyId) {
        log.info("【策略领域层-DefaultRuleEngine】: 规则规则树引擎装配, strategyId: {}", strategyId);
        RuleTreeEntity ruleTreeEntity = strategyRepository.queryRuleTreeByStrategyIdFromCache(strategyId);
        if(null != ruleTreeEntity) return ruleTreeEntity;

        ruleTreeEntity = strategyRepository.queryRuleTreeByStrategyId(strategyId);
        List<RuleTreeNodeEntity> ruleTreeNodeEntities = strategyRepository.queryRuleTreeNodeByStrategyId(strategyId);

        for (RuleTreeNodeEntity ruleTreeNodeEntity : ruleTreeNodeEntities) {
            List<RuleTreeLineEntity> ruleTreeLineEntities = strategyRepository.queryRuleTreeLineEntityByNodeFromAndStrategyId(ruleTreeNodeEntity.getNodeId(), strategyId);
            if(null == ruleTreeLineEntities) continue;;
            Map<String, RuleTreeLineEntity> ruleTreeLineEntityMap = new ConcurrentHashMap<>();
            for (RuleTreeLineEntity ruleTreeLineEntity : ruleTreeLineEntities) {
                ruleTreeLineEntityMap.put(ruleTreeLineEntity.getRuleTreeLineVO().getCode(), ruleTreeLineEntity);
            }
            ruleTreeNodeEntity.setRuleTreeLineEntityGroup(ruleTreeLineEntityMap);
        }

        Map<Long, RuleTreeNodeEntity> ruleTreeNodeEntityMap = new ConcurrentHashMap<>();
        for (RuleTreeNodeEntity ruleTreeNodeEntity : ruleTreeNodeEntities) {
            ruleTreeNodeEntityMap.put(ruleTreeNodeEntity.getNodeId(), ruleTreeNodeEntity);
        }
        ruleTreeEntity.setRuleTreeNodeEntityGroup(ruleTreeNodeEntityMap);
        strategyRepository.cacheRuleTree(ruleTreeEntity);
        return ruleTreeEntity;
    }


}
